# coding=utf-8

from typing import Dict, List
from generator.libsomeip.some_ip_type import Message, SomeIP
from generator.libsomeip.Common import isArray, isNormal, isString, isStruct, parseType
from string import Template
from utils.payload import TypeEnum

from utils.util import writeFile

templete_h=Template(
"""#pragma once

#include <array>
#include <memory>
#include <transfer/ITransfer.h>
#include "someip/someip_structs.h"
#include "someip/someip_signals.h"

namespace ecarx::transfer{
    
    class SomeIPManager{
        protected:
            std::shared_ptr<ITransfer> mSomeIPConn;
        public:
        SomeIPManager(std::shared_ptr<ITransfer> conn):mSomeIPConn(conn){

        }
${apis}
    };
}
"""
)

templete_cpp=Template(
"""#include "someip/SomeIPManager.h"
#include "serialize/Deserializer.h"
#include "serialize/Serializer.h"
#include <transfer/utils.h>

namespace ecarx::transfer{

${api_impls}
}
"""
)

templete_get_api_define=Template(
"""
        ${returnType} get${api_name}();
"""
)

##get基础类型的模板
templete_get_normal_api_impl=Template(
"""
${returnType} SomeIPManager::get${api_name}(){
    std::optional<Signal> value;
    if(mSomeIPConn != nullptr){
        value=mSomeIPConn->read(static_cast<int32_t>(${signalId}));
    }
    if (value.has_value()){
        return static_cast<${returnType}>(value->value.${prop}[0]);
    }

    return {};
}
"""
)
#get结构提类型的模板
templete_get_struct_api_impl=Template(
"""
${returnType} SomeIPManager::get${api_name}(){
    dra::com::Deserializer des;
    std::optional<Signal> value;
    if(mSomeIPConn != nullptr){
        value=mSomeIPConn->read(static_cast<int32_t>(${signalId}));
    }
    ${returnType} data;
    if (value.has_value()){
        des.setDeserialDataAddr(value->value.bytes.data(), value->value.bytes.size());
        if (!dra::com::deserialize(&des, data)) {
            printf("deserialize ${returnType} failure\\n");
        }
    }
    return data;
}
"""
)

#get数组类型的模板
templete_get_array_api_impl=Template(
"""
std::vector<${returnType}> SomeIPManager::get${api_name}(){
    dra::com::Deserializer des;
    std::optional<Signal> value;
    if(mSomeIPConn != nullptr){
        value=mSomeIPConn->read(static_cast<int32_t>(${signalId}));
    }
    std::vector<${returnType}> data{};
    if (value.has_value()){
        des.setDeserialDataAddr(value->value.bytes.data(), value->value.bytes.size());
        if (!dra::com::deserialize(&des, data)) {
            printf("deserialize ${returnType} vector failure\\n");
        }
    }
    return data;
}
"""
)

#get字符串类型的模板
templete_get_string_api_impl=Template(
"""
std::string SomeIPManager::get${api_name}(){
    std::optional<Signal> value;
    if(mSomeIPConn != nullptr){
        value=mSomeIPConn->read(static_cast<int32_t>(${signalId}));
    }
    if (value.has_value()){
        return value->value.stringValue;
    }
    return "";
}
"""
)

#set 函数定义
templete_set_api_define=Template(
"""
        bool set${api_name}(const ${param_type} value);
"""
)

#set函数基础类型模板实现
templete_set_base_type_impl=Template(
"""
bool SomeIPManager::set${api_name}(const ${param_type} value){
    Signal signal;
    signal.signalId=static_cast<uint32_t>(${signalId});
    signal.value.${member}={${convert_type}value};
    if(mSomeIPConn != nullptr){
        return mSomeIPConn->write(signal);
    }
    return false;
}
"""
)

#set函数结构体/Dynamic数组模板实现
templete_set_struct_api_impl=Template(
"""
bool SomeIPManager::set${api_name}(const ${param_type}&  value){
    dra::com::Serializer ser;
    Signal signal;
    signal.signalId=static_cast<uint32_t>(${signalId});
    if (dra::com::serialize(&ser, value)) {
        signal.value.bytes = ser.getSerialContent();
    }
    if(mSomeIPConn != nullptr){
        return mSomeIPConn->write(signal);
    }
    return false;
}
"""
)

#set函数数组类型的模板实现
templete_set_array_api_impl=Template(
"""
bool SomeIPManager::set${api_name}(const std::vector<${param_type}>& array){
    dra::com::Serializer ser;
    Signal signal;
    signal.signalId=static_cast<uint32_t>(${signalId});
    if (dra::com::serialize(&ser, array)) {
        signal.value.bytes = ser.getSerialContent();
    }
    if(mSomeIPConn != nullptr){
        return mSomeIPConn->write(signal);
    }
    return false;
}
"""
)

#set函数字符串类型的模板实现
templete_set_string_api_impl=Template(
"""
bool SomeIPManager::set${api_name}(const std::string & value){
    Signal signal;
    signal.signalId=static_cast<uint32_t>(${signalId});
    signal.value.stringValue=value;
    if(mSomeIPConn != nullptr){
        return mSomeIPConn->write(signal);
    }
    return false;
}
"""
)


def gen_someip_manager(someip:SomeIP):
    api_methods_define=[]
    api_methods_impl=[]
    for msg in someip.msg:
        idtItemList = someip.idtItemDict.get(msg.idtName, None)
        if idtItemList is None:
            print("!! lost idtname define:", msg.idtName)
            continue

        isGet = False
        isSet = False
        rcvSignalStr = ""
        sndSignalStr = ""
        methodStr = ""
        if msg.getterId != '0x0' or msg.eventId != '0x0':
            isGet = True
            rcvSignalStr = "SOMEIPRX::{}EventId".format(msg.msgName)

        if msg.setterId != '0x0':
            isSet = True
            methodStr = "{}Setter".format(msg.msgName)
            sndSignalStr = "SOMEIPTX::{}SetterId".format(msg.msgName)

        if msg.methodId != '0x0':
            isSet = True
            methodStr = "{}Method".format(msg.msgName)
            sndSignalStr = "SOMEIPTX::{}MethodId".format(msg.msgName)
        
        idtItem = idtItemList[0]
        if idtItem.isBaseType():
            dest_type, dest_len, convert_type, c_type = parseType(idtItem.idtType)
            if isGet == True:
                api_methods_define.append(templete_get_api_define.substitute(
                    api_name=msg.msgName,
                    returnType=c_type,
                ))
                api_methods_impl.append(templete_get_normal_api_impl.substitute(
                    signalId=rcvSignalStr,
                    api_name=msg.msgName,
                    returnType=c_type,
                    prop=dest_type
                ))
            if isSet == True:
                api_methods_define.append(templete_set_api_define.substitute(
                    api_name=msg.msgName,
                    param_type=c_type
                ))
                api_methods_impl.append(templete_set_base_type_impl.substitute(
                    signalId=sndSignalStr,
                    api_name=msg.msgName,
                    param_type=c_type,
                    member=dest_type,
                    convert_type=convert_type
                ))

        elif isArray(idtItem.idtType) == True:
            if isGet == True:
                api_methods_define.append(templete_get_api_define.substitute(
                    api_name=msg.msgName,
                    returnType="std::vector<{}>".format(idtItem.elementType),
                ))
                api_methods_impl.append(templete_get_array_api_impl.substitute(
                    signalId=rcvSignalStr,
                    api_name=msg.msgName,
                    returnType=idtItem.elementType,
                ))
                
            if isSet == True:
                api_methods_define.append(templete_set_api_define.substitute(
                    api_name=msg.msgName,
                    param_type="std::vector<{}>&".format(idtItem.elementType),
                ))
                api_methods_impl.append(templete_set_array_api_impl.substitute(
                    signalId=sndSignalStr,
                    api_name=msg.msgName,
                    param_type=idtItem.elementType,
                ))
            
        elif isStruct(idtItem.idtType) == True:
            if isGet == True:
                api_methods_define.append(templete_get_api_define.substitute(
                    api_name=msg.msgName,
                    returnType=msg.idtName,
                ))
                api_methods_impl.append(templete_get_struct_api_impl.substitute(
                    signalId=rcvSignalStr,
                    api_name=msg.msgName,
                    returnType=msg.idtName,
                ))
            if isSet == True:
                api_methods_define.append(templete_set_api_define.substitute(
                    api_name=msg.msgName,
                    param_type=msg.idtName+"&"
                ))
                api_methods_impl.append(templete_set_struct_api_impl.substitute(
                    signalId=sndSignalStr,
                    api_name=msg.msgName,
                    param_type=msg.idtName,
                ))
            # 支持一层遍历代码
            '''for e in idtItemList:
                idtItemList2 = someip.idtItemDict.get(e.elementType,None)
                if idtItemList2 == None:
                    print("cannot find elementType:", e.elementType)
                    continue
                
                property_type = ""
                idtItem2 = idtItemList2[0]
                if idtItem2.isBaseType():
                    dest_type, dest_len, convert_type, c_type = parseType(idtItem2.idtType)
                    if isGet == True:
                        api_methods_define.append(templete_get_api_define.substitute(
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            returnType=c_type,
                        ))
                        api_methods_impl.append(templete_get_normal_api_impl.substitute(
                            signalId=rcvSignalStr,
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            returnType=c_type,
                            prop=dest_type
                        ))
                    if isSet == True:
                        api_methods_define.append(templete_set_api_define.substitute(
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            param_type=c_type
                        ))
                        api_methods_impl.append(templete_set_base_type_impl.substitute(
                            signalId=sndSignalStr,
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            param_type=c_type,
                            member=dest_type,
                            convert_type=convert_type
                        ))
                elif isArray(idtItem.idtType) == True:
                    if isGet == True:
                        api_methods_define.append(templete_get_api_define.substitute(
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            returnType="std::vector<{}>".format(idtItem2.elementType),
                        ))
                        api_methods_impl.append(templete_get_array_api_impl.substitute(
                            signalId=rcvSignalStr,
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            returnType=idtItem2.elementType,
                        ))
                        
                    if isSet == True:
                        api_methods_define.append(templete_set_api_define.substitute(
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            param_type="std::vector<{}>&".format(idtItem2.elementType),
                        ))
                        api_methods_impl.append(templete_set_array_api_impl.substitute(
                            signalId=sndSignalStr,
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            param_type=idtItem2.elementType,
                        ))
                elif isStruct(idtItem.idtType) == True:
                    if isGet == True:
                        api_methods_define.append(templete_get_api_define.substitute(
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            returnType=e.elementType,
                        ))
                        api_methods_impl.append(templete_get_struct_api_impl.substitute(
                            signalId=rcvSignalStr,
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            returnType=e.elementType
                        ))
                    if isSet == True:
                        api_methods_define.append(templete_set_api_define.substitute(
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            param_type=e.elementType+"&"
                        ))
                        api_methods_impl.append(templete_set_struct_api_impl.substitute(
                            signalId=sndSignalStr,
                            api_name="{}_{}".format(msg.msgName, e.elementName),
                            param_type=e.elementType
                        ))
                        '''

    writeFile("./data/transfer/libsomeip/include/someip", "SomeIPManager.h",
              lambda file: file.write(templete_h.substitute(
                  apis="".join(api_methods_define)
              )))
    writeFile("./data/transfer/libsomeip/src", "SomeIPManager.cpp", lambda file:
              file.write(templete_cpp.substitute(
                  api_impls="".join(api_methods_impl),
              )))

    
